﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using intelliEssay.Interop.FontServices;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Wordprocessing;
using System.Text.RegularExpressions;

namespace intelliEssay.Interop
{
    public class StandardRunInfoEx : RunInfoEx
    {
        public StandardRunInfoEx(WordprocessingDocument wd, Run standardRun, HostApplications hostApplication = HostApplications.MsOffice2010)
            : base(wd, standardRun, hostApplication)
        {
        }

        /// <summary>
        /// Tests to see if the font related information for two runs are the same
        /// </summary>
        /// <param name="standardRunInfo">must call -verbose (CommandLineOptions.Verbose) when retrieving standardRunInfo</param>
        /// <param name="other">the runinfo compared against standard runinfo</param>
        /// <param name="valueUnequalMemberNames"></param>
        /// <returns></returns>
        public bool SemanticEqual(RunInfoEx other, out List<string> valueUnequalMemberList)
        {
            
            valueUnequalMemberList = new List<string>();
            if (other.runInfo.Text.Trim() == "") return true;
            if (this.runInfo.CharacterScale != other.runInfo.CharacterScale)
            {
                valueUnequalMemberList.Add("characterscale");
            }
            if (this.runInfo.Color != other.runInfo.Color)
            {
                valueUnequalMemberList.Add("color");
            }
            var zhcnFont = this.runInfo.GetFont(ha, "zhcn");
            var otherCultureFont = this.runInfo.GetFont(ha, "other");
            if (RunInfo.CHNTest.IsMatch(other["text"][0].ToString()))
            {
                if (zhcnFont != other.runInfo.GetFont(other.ha, "zhcn"))
                {
                    valueUnequalMemberList.Add("fontfamily");
                }
            }
            else
            {
                if (otherCultureFont != other.runInfo.GetFont(other.ha, "other"))
                {
                    valueUnequalMemberList.Add("fontfamily");
                }
            }
            if (this.runInfo.FontSize != other.runInfo.FontSize)
            {
                valueUnequalMemberList.Add("fontsize");
            }
            if (this.runInfo.IsBold != other.runInfo.IsBold)
            {
                valueUnequalMemberList.Add("isbold");
            }
            if (this.runInfo.IsItalic != other.runInfo.IsItalic)
            {
                valueUnequalMemberList.Add("isitalic");
            }
            if (this.runInfo.IsUnderline != other.runInfo.IsUnderline)
            {
                valueUnequalMemberList.Add("isunderline");
            }
            if (this.runInfo.Spacing != other.runInfo.Spacing)
            {
                valueUnequalMemberList.Add("spacing");
            }
            if (this.runInfo.VerticalPositionAlignment != other.runInfo.VerticalPositionAlignment)
            {
                valueUnequalMemberList.Add("verticaltextalignment");
            }
            return valueUnequalMemberList.Count == 0;
        }
    }

    /// <summary>
    /// This is a shorthand wrapper for RunInfo.
    /// Internally, a RunInfo is built using Helper.GetRunInfo(). 
    /// <para>This implementation is subject to change as is on 12.22</para>
    /// </summary>
    public class RunInfoEx
    {
        internal RunInfo runInfo;
        internal HostApplications ha;
        public RunInfoEx(WordprocessingDocument wd, Run run, HostApplications hostApplication = HostApplications.MsOffice2010)
        {
            ha = hostApplication;
            intelliEssay.Interop.FontServices.RunInfoHelper helper = new RunInfoHelper(wd);
            // do not care about compiler warning. Internal use of helper is allowed.
            runInfo = helper.GetRunInfo(run);
        }

        public dynamic this[string propertyName]
        {
            get
            {
                return GetPropertyInfo(propertyName);
            }
        }

        /// <summary>
        /// Queries run-related information.
        /// This internally calls RunInfo properties.
        /// </summary>
        /// <param name="propertyName">the property name of RunInfo in query</param>
        /// <returns>the value of the property</returns>
        /// <remarks>Reflection is not used due to effeciency issues.</remarks>
        internal dynamic GetPropertyInfo(string propertyName, string additionalCommand = "")
        {
            propertyName = propertyName.ToLowerInvariant();
            switch (propertyName)
            {
                case "characterscale":
                    return runInfo.CharacterScale;
                case "color":
                    return runInfo.Color;
                case "runfonts":
                case "font":
                case "fontfamily":
                    return runInfo.GetFont(ha, additionalCommand);
                case "fontsize":
                    return runInfo.FontSize;
                case "isbold":
                case "bold":
                case "w:b":
                    return runInfo.IsBold;
                case "isitalic":
                case "italic":
                case "w:i":
                    return runInfo.IsItalic;
                case "isunderline":
                case "underline":
                case "w:u":
                    return runInfo.IsUnderline;
                case "text":
                    return runInfo.Text;
                case "verticaltextalignment":
                    return runInfo.VerticalPositionAlignment;
                case "spacing":
                case "w:s":
                    return runInfo.Spacing;
                default:
                    throw new NotImplementedException("The query for property " + propertyName + " isn't supported in this build");
            }
        }

        public dynamic GetSemanticValue(string memberName)
        {
            if (memberName != "fontsize")
            {
                return this[memberName];
            }
            return (int.Parse(runInfo.FontSize) / 2).ToString();
        }
    }
}
